package testadventure;

import edu.clemson.cs.hamptos.adventure.AdventureCommand;
import edu.clemson.cs.hamptos.adventure.AdventureEngine;
import edu.clemson.cs.hamptos.adventure.AdventureTarget;
import edu.clemson.cs.hamptos.adventure.AdventureWindow;
import edu.clemson.cs.hamptos.adventure.DoNotUnderstandException;
import edu.clemson.cs.hamptos.adventure.NoSuchTargetException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Scanner;
import java.util.StringTokenizer;

/**
 * <p>Primary implementation for <code>AdventureTarget</code>,
 * subclasses should mainly extend the constructor, not the fields and 
 * methods</p>
 * @author Nicks
 */
public class BaseItem implements AdventureTarget {
    protected BaseItem() {
        
    }
    //protected so that no outsider can call this constructor directly,
    //   use subclasses
    protected BaseItem(StringBuilder inBlob)
    {
        Scanner blobScan = new Scanner(inBlob.toString());
        blobScan.useDelimiter(";\r\n");
        
        id = blobScan.next();
        
        Scanner nameScan = new Scanner(blobScan.next());
        nameScan.useDelimiter(" ");
        name = nameScan.next();
        if (nameScan.hasNext())
        {
            descriptor = nameScan.next();
        }
        
        Scanner descrScan = new Scanner(blobScan.next());
        descrScan.useDelimiter("-\r\n");
        description = descrScan.next();
        while(descrScan.hasNext())
        {
            unsortedDescriptions.add(descrScan.next());
        }
        
        shortDescr = blobScan.next();
        
        Scanner statScan = new Scanner(blobScan.next());
        statScan.useDelimiter("\r\n");
        while (statScan.hasNext())
        {
            Scanner singleStatScan = new Scanner(statScan.next());
            String key = singleStatScan.next();
            Integer value = new Integer(singleStatScan.next());
            stats.put(key, value);
        }
        
        if(stats.containsKey("enabled"))
        {
            String insTxt = unsortedDescriptions.poll();
            if (insTxt != null)
            {
                enabledTxt = insTxt;
            }
            insTxt = unsortedDescriptions.poll();
            if (insTxt != null)
            {
                disabledTxt = insTxt;
            }
            insTxt = unsortedDescriptions.poll();
            if (insTxt != null)
            {
                activatedTxt = insTxt;
            }
            insTxt = unsortedDescriptions.poll();
            if (insTxt != null)
            {
                deactivatedTxt = insTxt;
            }
        }
        
        
        //removes read fields from inBlob
        inBlob.setLength(0);
        while (blobScan.hasNext())
        {
            inBlob.append(blobScan.next()).append(";\r\n");
        }
    }
    
    //Class Variables
    ////Needs to be a unique identifier
    protected String id;
    protected String name;
    //Adjective that applies to the object
    protected String descriptor = "";
    //descriptions of the object
    protected String description= "";
    protected String shortDescr = "";
    
    protected String enabledTxt = "";
    protected String disabledTxt = "";
    
    protected String activatedTxt = "";
    protected String deactivatedTxt = "";
    
    //list of things triggered by tampering with this item
    protected HashSet<String> listeners = new HashSet<String>();
    
    //Acceptable Words, organized based on sentence location
    //if DO
    protected HashMap<String, VContainer> accDOVerbs = new HashMap<String, 
                                                           VContainer>();
    //if IO
    protected HashMap<String, VContainer> accIOVerbs = new HashMap<String, 
                                                           VContainer>();
    //if DO with IO
    protected HashSet<String> accIOs = new HashSet<String>();
    
    /**
     * <p>contains misc. flags for Action Interface methods</p>
     */
    public HashMap<String, Integer> stats = new HashMap<String, Integer>();
    LinkedList<String> unsortedDescriptions = new LinkedList<String>();
    ////
    
    @Override
    public String getID()
    {
        return id;
    }
    
    /**
     * Tests to see if the BaseItem can be properly referred to by the text
     * 
     * @param text needs to be a not empty string and 
     * needs to be stripped of ALL articles prior to function call
     * 
     * @return true if it can be referred to by the text, false if it cannot
     */
    @Override
    public boolean canBeReferredToAs(String text) {
        if ((text == null)||(text.equals("")))
        {
            return false;
        }
        
        StringTokenizer strip = new StringTokenizer(text);
        //if it has more than 2 words, could make this PRECONDITION
        if (strip.countTokens() > 2)
        {
            return false;
        }
        if (strip.countTokens() == 1)
        {
            if (strip.nextToken().equals(name))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        String adjective = strip.nextToken();
        if (descriptor.equals(adjective))
        {
            if (strip.nextToken().equals(name))
            {
                return true;
            }
        }
        return false;
    }

    @Override
    public String getShortDescription() {
        if (stats.get("enabled") == 0)
        {
            return shortDescr;
        }
        else
        {
            return shortDescr;
        }
    }

    @Override
    public String getDescription() {
        if (stats.get("enabled") == 0)
        {
            return disabledTxt;
        }
        else
        {
            return enabledTxt;
        }
    }
    
    @Override
    public void doCommandWith(AdventureCommand c, AdventureEngine e, 
                              AdventureWindow w) 
                              throws DoNotUnderstandException {
        throw new DoNotUnderstandException(c);
    }

    @Override
    public boolean checkVerbAsIO(String v) {
        if (accIOVerbs.containsKey(v))
        {
            return true;
        }
        return false;
    }

    @Override
    public boolean checkVerbAsDO(String v) {
        if (accDOVerbs.containsKey(v))
        {
            return true;
        }
        return false;
    }

    @Override
    public boolean checkIO(String io) {
        if (accIOs.contains(io))
        {
            return true;
        }
        return false;
    }

    @Override
    public HashMap<String, Integer> getStats() {
        return stats;
    }
    
    @Override
    public String toString(){
        return id;
    }
    
    /**
     * <p>Fills the fields of the clone with copies of the original</p>
     * @param cl 
     */
    protected void fillClone(BaseItem cl)
    {
        cl.accDOVerbs = new HashMap<String, VContainer>(accDOVerbs);
        cl.accIOVerbs = new HashMap<String, VContainer> (accIOVerbs);
        cl.accIOs = new HashSet<String>(accIOs);
        cl.description = description;
        cl.descriptor = descriptor;
        cl.id = id;
        cl.name = name;
        cl.stats = new HashMap<String, Integer>(stats);
        cl.shortDescr = shortDescr;
        
        cl.enabledTxt = enabledTxt;
        cl.disabledTxt = disabledTxt;
        cl.activatedTxt = activatedTxt;
        cl.deactivatedTxt = deactivatedTxt;
    }
    
    @Override
    public AdventureTarget clone()
    {
        BaseItem cl = new BaseItem();
        cl.fillClone(cl);
        
        return cl;
    }

    @Override
    public void doCommandTo(AdventureCommand c, AdventureEngine e, 
                            AdventureWindow w) throws DoNotUnderstandException {
        throw new DoNotUnderstandException(c, "You can't " + c.getVerb() + " "
                                            + getShortDescription());
    }

    @Override
    public void addListener(String target) {
        listeners.add(target);
    }

    @Override
    public void removeListener(String target) {
        listeners.remove(target);
    }

    @Override
    public void notifyListeners(AdventureEngine e, AdventureWindow w) {
        Iterator<String> it = listeners.iterator();
        while(it.hasNext())
        {
            try {
                AdventureTarget t = e.getPlayerLocation().
                                    containsLocalTarget(it.next());
                t.listen(e, w);
            } catch (NoSuchTargetException ex) {
                //suppress, shouldn't happen
                w.println("Oops, Listener wasn't there..." + ex.getItemName());
            }
        }
    }

    @Override
    public void listen(AdventureEngine e, AdventureWindow w) {
        if (stats.get("enabled") == 0)
        {
            stats.put("enabled", 1);
            w.println(activatedTxt);
        }
        else if(stats.get("enabled") == 1)
        {
            stats.put("enabled", 0);
            w.println(deactivatedTxt);
        }
    }

    @Override
    public String getName() {
        return name;
    }
}
